#ifndef AVALON_BASE_HPP
#define AVALON_BASE_HPP
#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

namespace Avalon {
  struct BaseEnumerator;
  struct BaseMask;
  template<typename T> class Carry;
  template<typename T, typename E> class Enumerator;
  template<typename T> class Handle;
  template<typename T> class Initializer;
  class InstantiationNotSupportedException;
  template<typename T, unsigned int S, typename K> struct Mask;
  class NotImplementedException;
  template<typename T> class Out;
  template<typename T> class Singleton;

  //! Returns <code>true</code> iff this platform uses a big-endian byte order.
  bool IsBigEndian();

  //! Reverses the byte order of a value.
  /*!
    \param value The value whose bytes are to be reversed.
    \return The given <i>value</i> with its bytes reversed.
  */
  template<typename T>
  T ReverseBytes(T value) {
    T reversed;
    const char* i = reinterpret_cast<const char*>(&value) + sizeof(T) - 1;
    for(int j = 0; j < sizeof(T); ++j) {
      *(reinterpret_cast<char*>(&reversed) + j) = *i;
      --i;
    }
    return reversed;
  }

  //! Returns the native representation of a big endian value.
  /*!
    \param value The value.
    \return The native representation of the specified <i>value</i>.
  */
  template<typename T>
  T FromBigEndian(T value) {
    if(IsBigEndian()) {
      return value;
    }
    return ReverseBytes(value);
  }

  //! Returns the native representation of a little endian value.
  /*!
    \param value The value.
    \return The little-endian representati of the specified <i>value</i>.
  */
  template<typename T>
  T FromLittleEndian(T value) {
    if(!IsBigEndian()) {
      return value;
    }
    return ReverseBytes(value);
  }

  //! Returns the big-endian representation of a value.
  /*!
    \param value The value.
    \return The big-endian representation of the specified <i>value</i>.
  */
  template<typename T>
  T ToBigEndian(T value) {
    if(IsBigEndian()) {
      return value;
    }
    return ReverseBytes(value);
  }

  //! Returns the little-endian representation of a value.
  /*!
    \param value The value.
    \return The little-endian representation of the specified <i>value</i>.
  */
  template<typename T>
  T ToLittleEndian(T value) {
    if(!IsBigEndian()) {
      return value;
    }
    return ReverseBytes(value);
  }

  //! Returns the ceiling of a number to a point.
  /*!
    \param value The value to ceil.
    \param point The point to ceil to.
    \return The <i>value</i> ceiled to the specified <i>point</i>.
  */
  double Ceil(double value, double point = 1.0);

  //! Returns the ceiling of a number to a point.
  /*!
    \param value The value to ceil.
    \param point The point to ceil to.
    \return The <i>value</i> ceiled to the specified <i>point</i>.
  */
  int Ceil(int value, int point = 1);

  //! Returns the floor of a number to a point.
  /*!
    \param value The value to floor.
    \param point The point to floor to.
    \return The <i>value</i> floored to the specified <i>point</i>.
  */
  double Floor(double value, double point = 1.0);

  //! Returns the floor of a number to a point.
  /*!
    \param value The value to floor.
    \param point The point to floor to.
    \return The <i>value</i> floored to the specified <i>point</i>.
  */
  int Floor(int value, int point = 1);

  //! Rounds a number to a point.
  /*!
    \param value The value to round.
    \param point The point to round to.
    \return The <i>value</i> rounded to the specified <i>point</i>.
  */
  double Round(double value, double point = 1.0);

  //! Rounds a number to a point.
  /*!
    \param value The value to round.
    \param point The point to round to.
    \return The <i>value</i> rounded to the specified <i>point</i>.
  */
  int Round(int value, int point = 1);

  //! Checks if the operating system signalled to shutdown the application.
  bool ReceivedKillEvent();
}

#endif // AVALON_BASE_HPP
